home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************
- * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
- * is provided to you without charge, and with no warranty. You may give *
- * away copies of JOVE, including sources, provided that this notice is *
- * included in all the files. *
- ***************************************************************************/
-
- #include "jove.h"
- #include "ctype.h"
- #include "termcap.h"
- #include "disp.h"
- #include "fp.h"
- #include <signal.h>
- #include <errno.h>
- #define HAVE_STRERROR 1
-
- #ifdef MAC
- # include "mac.h"
- #else
- # ifdef STDARGS
- # include <stdarg.h>
- # else
- # include <varargs.h>
- # endif
- #endif
-
- #ifdef MSDOS
- #include <time.h>
- #endif
-
- const struct cmd *
- FindCmd(proc)
- register void (*proc) proto((void));
- {
- register const struct cmd *cp;
-
- for (cp = commands; cp->Name; cp++)
- if (cp->c_proc == proc)
- return cp;
- return NULL;
- }
-
- bool Interactive = NO; /* True when we invoke with the command handler? */
- data_obj *LastCmd;
- char *ProcFmt = ": %f ";
-
- void
- ExecCmd(cp)
- register data_obj *cp;
- {
- LastCmd = cp;
- if (cp->Type & MAJOR_MODE) {
- SetMajor((cp->Type >> 8));
- } else if (cp->Type & MINOR_MODE) {
- TogMinor((cp->Type >> 8));
- } else switch (cp->Type&TYPEMASK) {
- case MACRO:
- do_macro((struct macro *) cp);
- break;
-
- case FUNCTION:
- {
- register struct cmd *cmd = (struct cmd *) cp;
-
- if (cmd->c_proc) {
- if ((cmd->Type & MODIFIER) &&
- (BufMinorMode(curbuf, ReadOnly))) {
- rbell();
- message("[Buffer is read-only]");
- } else
- (*cmd->c_proc)();
- }
- }
- }
- }
-
- Line *
- lastline(lp)
- register Line *lp;
- {
- register Line *next;
-
- while ((next = lp->l_next) != NULL)
- lp = next;
- return lp;
- }
-
- char key_strokes[100],
- *keys_p = key_strokes;
-
- void
- pp_key_strokes(buffer, size)
- char *buffer;
- size_t size;
- {
- char *buf_end = buffer + size - 1,
- *kp = key_strokes,
- c;
-
- *buffer = '\0';
- while ((c = *kp++) != '\0') {
- swritef(buffer, (size_t) (buf_end-buffer), "%p ", c);
- buffer += strlen(buffer);
- if (buffer >= buf_end)
- break;
- }
- }
-
- private int *slowp = NULL; /* for waitchar() */
-
- private SIGRESULT
- slowpoke(junk)
- int junk;
- {
- int save_errno = errno; /* Subtle, but necessary! */
- char buffer[100];
-
- if (slowp)
- *slowp = YES;
- pp_key_strokes(buffer, sizeof (buffer));
- f_mess(buffer);
- errno = save_errno;
- SIGRETURN;
- }
-
- #ifdef UNIX
- # ifdef BSD4_2
- # define N_SEC 1 /* will be precisely 1 second on 4.2 */
- # else
- # define N_SEC 2 /* but from 1 to 2 seconds otherwise */
- # endif
- #else /* !UNIX */
- # define N_SEC 1
- int in_macro();
- #endif /* !UNIX */
-
- int
- waitchar(slow)
- int *slow;
- {
- int c;
- #ifdef UNIX
- unsigned int old_time;
- SIGRESULT (*oldproc) proto((int));
- #else /* !UNIX */
- long sw, time();
- #endif /* !UNIX */
-
- slowp = slow;
-
- if (in_macro()) /* make macros faster ... */
- return getch();
-
- /* If slow is a valid pointer and it's value is yes, then
- we know we have already been slow during this sequence,
- so we just wait for the character and then echo it. */
- if (slow != NULL && *slow == YES) {
- c = getch();
- slowpoke(0);
- return c;
- }
- #ifdef UNIX
- oldproc = signal(SIGALRM, slowpoke);
-
- if ((old_time = alarm((unsigned) N_SEC)) == 0)
- old_time = UpdFreq;
- c = getch();
- (void) alarm(old_time);
- (void) signal(SIGALRM, oldproc);
-
- if (slow != NULL && *slow == YES)
- slowpoke(0);
- return c;
-
- #else /* !UNIX */
- #ifdef MAC
- Keyonly = YES;
- if (charp() || in_macro()) {
- c = getch(); /* to avoid flicker */
- if (slow != NULL && *slow == YES)
- slowpoke();
- return c;
- }
- #endif
- time(&sw);
- sw += N_SEC;
- while (time(NULL) <= sw)
- if (charp() || in_macro())
- return getch();
- #ifdef MAC
- menus_off();
- #endif
- slowpoke();
- c = getch();
- slowpoke();
-
- return c;
- #endif /* !UNIX */
- }
-
- char *
- StrIndex(dir, buf, charpos, what)
- int dir; /* FORWARD or BACKWARD */
- register char *buf;
- int charpos;
- register int what;
- {
- register char *cp = &buf[charpos];
- register int c;
-
- if (dir > 0) {
- while ((c = *cp++) != '\0')
- if ((c == what) != '\0')
- return (cp - 1);
- } else {
- while (cp >= buf && (c = *cp--)!='\0')
- if (c == what)
- return (cp + 1);
- }
- return NULL;
- }
-
- bool
- blnkp(buf)
- register char *buf;
- {
- register char c;
-
- do ; while ((c = *buf++)!='\0' && (c == ' ' || c == '\t'));
- return c == 0; /* It's zero if we got to the end of the Line */
- }
-
- bool
- within_indent()
- {
- register char c;
- register int i;
-
- i = curchar;
- do ; while (--i >= 0 && ((c = linebuf[i]) == ' ' || c == '\t'));
- return i < 0; /* it's < 0 if we got to the beginning */
- }
-
- Line *
- next_line(line, num)
- register Line *line;
- register int num;
- {
- if (num < 0)
- return prev_line(line, -num);
- if (line)
- while (--num >= 0 && line->l_next != NULL)
- line = line->l_next;
- return line;
- }
-
- Line *
- prev_line(line, num)
- register Line *line;
- register int num;
- {
- if (num < 0)
- return next_line(line, -num);
- if (line)
- while (--num >= 0 && line->l_prev != NULL)
- line = line->l_prev;
- return line;
- }
-
- void
- DotTo(line, col)
- Line *line;
- int col;
- {
- Bufpos bp;
-
- bp.p_line = line;
- bp.p_char = col;
- SetDot(&bp);
- }
-
- /* If bp->p_line is != current line, then save current line. Then set dot
- to bp->p_line, and if they weren't equal get that line into linebuf. */
-
- void
- SetDot(bp)
- register Bufpos *bp;
- {
- register int notequal;
-
- if (bp == NULL)
- return;
-
- notequal = bp->p_line != curline;
- if (notequal)
- lsave();
- if (bp->p_line)
- curline = bp->p_line;
- if (notequal)
- getDOT();
- curchar = bp->p_char;
- if (curchar > length(curline))
- curchar = length(curline);
- }
-
- void
- ToLast()
- {
- SetLine(curbuf->b_last);
- Eol();
- }
-
- int MarkThresh = 22; /* average screen size ... */
- static int line_diff;
-
- int
- LineDist(nextp, endp)
- register Line *nextp,
- *endp;
- {
- (void) inorder(nextp, 0, endp, 0);
- return line_diff;
- }
-
- int
- inorder(nextp, char1, endp, char2)
- register Line *nextp,
- *endp;
- int char1,
- char2;
- {
- register Line *prevp = nextp;
-
- line_diff = 0;
- if (nextp == endp)
- return char1 < char2;
-
- while (nextp && prevp) {
- nextp = nextp->l_next;
- prevp = prevp->l_prev;
- line_diff += 1;
- if (nextp == endp)
- return TRUE;
- if (prevp == endp)
- return FALSE;
- }
- while (nextp!=NULL && nextp!=endp) {
- nextp = nextp->l_next;
- line_diff += 1;
- }
- while (prevp!=NULL && prevp!=endp) {
- prevp = prevp->l_prev;
- line_diff += 1;
- }
- /* nextp == prevp implies both are NULL: the lines are not ordered */
- return nextp==prevp? -1 : nextp==endp;
- }
-
- void
- PushPntp(line)
- register Line *line;
- {
- if (LineDist(curline, line) >= MarkThresh)
- set_mark();
- }
-
- void
- ToFirst()
- {
- SetLine(curbuf->b_first);
- }
-
- int
- length(line)
- Line *line;
- {
- return strlen(lcontents(line));
- }
-
- void
- to_word(dir)
- register int dir;
- {
- register char c;
-
- if (dir == FORWARD) {
- while ((c = linebuf[curchar]) != '\0' && !jisword(c))
- curchar += 1;
- if (eolp()) {
- if (curline->l_next == NULL)
- return;
- SetLine(curline->l_next);
- to_word(dir);
- return;
- }
- } else {
- while (!bolp() && (c = linebuf[curchar - 1], !jisword(c)))
- curchar -= 1;
- if (bolp()) {
- if (curline->l_prev == NULL)
- return;
- SetLine(curline->l_prev);
- Eol();
- to_word(dir);
- }
- }
- }
-
- /* Are there any modified buffers? Allp means include B_PROCESS
- buffers in the check. */
-
- bool
- ModBufs(allp)
- bool allp;
- {
- register Buffer *b;
-
- for (b = world; b != NULL; b = b->b_next)
- if (b->b_type != B_SCRATCH
- && (b->b_type == B_FILE || allp)
- && IsModified(b))
- return YES;
- return NO;
- }
-
- char *
- filename(b)
- register Buffer *b;
- {
- return b->b_fname ? pr_name(b->b_fname, YES) : "[No file]";
- }
-
- char *
- itoa(num)
- register int num;
- {
- static char line[15];
-
- swritef(line, sizeof(line), "%d", num);
- return line;
- }
-
- int
- min(a, b)
- register int a,
- b;
- {
- return (a < b) ? a : b;
- }
-
- int
- max(a, b)
- register int a,
- b;
- {
- return (a > b) ? a : b;
- }
-
- void
- tiewind(w, bp)
- register Window *w;
- register Buffer *bp;
- {
- int not_tied = (w->w_bufp != bp);
-
- UpdModLine = YES; /* kludge ... but speeds things up considerably */
- w->w_line = bp->b_dot;
- w->w_char = bp->b_char;
- w->w_bufp = bp;
- if (not_tied)
- CalcWind(w); /* ah, this has been missing since the
- beginning of time! */
- }
-
- char *
- lcontents(line)
- register Line *line;
- {
- if (line == curline)
- return linebuf;
- else
- return lbptr(line);
- }
-
- char *
- ltobuf(line, buf)
- Line *line;
- char *buf;
- {
- if (line == curline) {
- if (buf != linebuf)
- strcpy(buf, linebuf);
- Jr_Len = strlen(linebuf);
- } else
- getline(line->l_dline, buf);
- return buf;
- }
-
- void
- DOTsave(buf)
- Bufpos *buf;
- {
- buf->p_line = curline;
- buf->p_char = curchar;
- }
-
- /* Return none-zero if we had to rearrange the order. */
-
- bool
- fixorder(line1, char1, line2, char2)
- register Line **line1,
- **line2;
- register int *char1,
- *char2;
- {
- Line *tline;
- int tchar;
-
- if (inorder(*line1, *char1, *line2, *char2))
- return NO;
-
- tline = *line1;
- tchar = *char1;
- *line1 = *line2;
- *char1 = *char2;
- *line2 = tline;
- *char2 = tchar;
-
- return YES;
- }
-
- bool
- inlist(first, what)
- register Line *first,
- *what;
- {
- while (first) {
- if (first == what)
- return YES;
- first = first->l_next;
- }
- return NO;
- }
-
- /* Make `buf' (un)modified and tell the redisplay code to update the modeline
- if it will need to be changed. */
-
- int ModCount = 0;
-
- void
- modify()
- {
- if (!curbuf->b_modified) {
- UpdModLine = YES;
- curbuf->b_modified = YES;
- }
- DOLsave = YES;
- if (!Asking)
- ModCount += 1;
- }
-
- void
- unmodify()
- {
- if (curbuf->b_modified) {
- UpdModLine = YES;
- curbuf->b_modified = NO;
- }
- }
-
- int
- numcomp(s1, s2)
- register char *s1,
- *s2;
- {
- register int count = 0;
-
- while (*s1 != '\0' && *s1++ == *s2++)
- count += 1;
- return count;
- }
-
- char *
- copystr(str)
- char *str;
- {
- char *val;
-
- if (str == NULL)
- return NULL;
- val = emalloc((size_t) (strlen(str) + 1));
-
- strcpy(val, str);
- return val;
- }
-
- #ifndef byte_copy
- void
- byte_copy(from, to, count)
- UnivConstPtr *from;
- UnivPtr *to;
- register size_t count;
- {
- register const char *p = from;
- register char *q = to;
-
- if (count != 0) {
- do *q++ = *p++; while (--count != 0);
- }
- }
- #endif
-
- void
- len_error(flag)
- int flag;
- {
- char *mesg = "[line too long]";
-
- if (flag == COMPLAIN)
- complain(mesg);
- else
- error(mesg);
- }
-
- /* Insert num number of c's at offset atchar in a linebuf of LBSIZE */
-
- void
- ins_c(c, buf, atchar, num, max)
- int c;
- char *buf;
- int atchar,
- num,
- max;
- {
- register char *pp, *pp1;
- register int len;
- int numchars; /* number of characters to copy forward */
-
- if (num <= 0)
- return;
- len = atchar + strlen(&buf[atchar]);
- if (len + num >= max)
- len_error(COMPLAIN);
- pp = &buf[len + 1]; /* + 1 so we can --pp (not pp--) */
- pp1 = &buf[len + num + 1];
- numchars = len - atchar;
- while (numchars-- >= 0)
- *--pp1 = *--pp;
- pp = &buf[atchar];
- while (--num >= 0)
- *pp++ = c;
- }
-
- int
- TwoBlank()
- {
- register Line *next = curline->l_next;
-
- return ((next != NULL) &&
- (*(lcontents(next)) == '\0') &&
- (next->l_next != NULL) &&
- (*(lcontents(next->l_next)) == '\0'));
- }
-
- void
- linecopy(onto, atchar, from)
- register char *onto,
- *from;
- int atchar;
- {
- register char *endp = &onto[LBSIZE];
-
- onto += atchar;
-
- do {
- if (onto >= endp)
- len_error(ERROR);
- } while ((*onto++ = *from++) != '\0');
- }
-
- char *
- IOerr(err, file)
- char *err, *file;
- {
- return sprint("Couldn't %s \"%s\".", err, file);
- }
-
- #ifdef UNIX
- void
- dopipe(p)
- int *p;
- {
- if (pipe(p) == -1)
- complain("[Pipe failed: %s]", strerror(errno));
- }
-
- void
- pipeclose(p)
- int *p;
- {
- (void) close(p[0]);
- (void) close(p[1]);
- }
- #endif /* UNIX */
-
- /* NOSTRICT */
-
- UnivPtr
- emalloc(size)
- size_t size;
- {
- register UnivPtr ptr;
-
- if ((ptr = malloc(size)) == NULL) {
- /* Try garbage collecting lines */
- GCchunks();
- if ((ptr = malloc(size)) == NULL) {
- /* Uh ... Oh screw it! */
- error("[Out of memory] ");
- /* NOTREACHED */
- }
- }
- return ptr;
- }
-
- UnivPtr
- erealloc(ptr, size)
- UnivPtr ptr;
- size_t size;
- {
- if ((ptr = realloc(ptr, size)) == NULL) {
- /* no second chance for realloc! */
- error("[out of memory]");
- /* NOTREACHED */
- }
- return ptr;
- }
-
- /* Return the basename of file F. */
-
- char *
- basename(f)
- register char *f;
- {
- register char *cp;
-
- if ((cp = strrchr(f, '/')) != NULL)
- return cp + 1;
- else
- #ifdef MSDOS
- if (cp = strrchr(f, '\\'))
- return cp + 1;
- else
- if (cp = strrchr(f, ':'))
- return cp + 1;
- #endif /* MSDOS */
- return f;
- }
-
- void
- push_env(savejmp)
- jmp_buf savejmp;
- {
- byte_copy((UnivPtr) mainjmp, (UnivPtr) savejmp, sizeof (jmp_buf));
- }
-
- void
- pop_env(savejmp)
- jmp_buf savejmp;
- {
- byte_copy((UnivPtr) savejmp, (UnivPtr) mainjmp, sizeof (jmp_buf));
- }
-
- /* get the time buf, designated by *timep, from FROM to TO. */
- char *
- get_time(timep, buf, from, to)
- time_t *timep;
- char *buf;
- int from,
- to;
- {
- time_t now;
- char *cp;
-
- if (timep != NULL)
- now = *timep;
- else
- (void) time(&now);
- cp = ctime(&now) + from;
- #ifndef MSDOS
- if (to == -1)
- #else /* MSDOS */
- if ((to == -1) && (cp[strlen(cp)-1] == '\n'))
- #endif /* MSDOS */
- cp[strlen(cp) - 1] = '\0'; /* Get rid of \n */
- else
- cp[to - from] = '\0';
- if (buf) {
- strcpy(buf, cp);
- return buf;
- } else {
- return cp;
- }
- }
-
- int
- casecmp(s1, s2)
- register char *s1,
- *s2;
- {
- if (s1==NULL || s2==NULL)
- return 1; /* which is not zero ... */
- while (CharUpcase(*s1) == CharUpcase(*s2++))
- if (*s1++ == '\0')
- return 0;
- return (*s1 - *--s2);
- }
-
- int
- casencmp(s1, s2, n)
- register char *s1,
- *s2;
- register size_t n;
- {
- if (s1==NULL || s2==NULL)
- return 1; /* which is not zero ... */
- for (;;) {
- if (n == 0)
- return 0;
- n--;
- if (CharUpcase(*s1) != CharUpcase(*s2++))
- return *s1 - *--s2;
- if (*s1++ == '\0')
- return 0;
- }
- }
-
- void
- null_ncpy(to, from, n)
- char *to,
- *from;
- size_t n;
- {
- (void) strncpy(to, from, n);
- to[n] = '\0';
- }
-
- /* Tries to pause for delay/10 seconds OR until a character is typed
- at the keyboard. This works well on BSD4_2 and not so well on the
- rest. */
-
- #ifdef BSD4_2
- # ifndef BSD2_10
- # include <sys/time.h>
- # endif
- #endif
-
- #ifdef MSDOS
- # include <bios.h>
- # include <dos.h>
- #endif
-
- void
- SitFor(delay)
- int delay;
- {
- #ifdef MAC
- long start,
- end;
-
- #define Ticks ((long *) 0x16A) /* 1/60 sec */
- Keyonly = YES;
- redisplay();
- start = *Ticks;
-
- end = start + delay * 6;
- do {
- if ((InputPending = charp()) != NO)
- break;
- } while (*Ticks < end);
- #undef Ticks
-
- #else /* !MAC */
-
- #ifndef MSDOS
- if (!charp()) {
- #if defined(BSD4_2) && !defined(BSD2_10)
- struct timeval timer;
- long readfds = 1;
-
- /* So messages that aren't error messages don't
- * hang around forever.
- * Gross that I had to snarf this from getch()
- */
- if (!UpdMesg && !Asking && mesgbuf[0] && !errormsg)
- message(NullStr);
- redisplay();
-
- timer.tv_sec = (delay / 10);
- timer.tv_usec = (delay % 10) * 100000;
- select(1, &readfds, (long *)NULL, (long *)NULL, &timer);
- #else /* !(defined(BSD4_2) && !defined(BSD2_10)) */
- /* Pause by spitting NULs at the terminal. Ugh! */
- static const int cps[] = {
- 0,
- 5,
- 7,
- 11,
- 13,
- 15,
- 20,
- 30,
- 60,
- 120,
- 180,
- 240,
- 480,
- 960,
- 1920,
- 1920,
- };
- register int nchars,
- check_cnt;
-
- nchars = (delay * cps[ospeed]) / 10;
- check_cnt = BufSize;
- redisplay();
- if (!NP) {
- while ((--nchars > 0) && !InputPending) {
- jputchar(PC);
- if (--check_cnt == 0) {
- check_cnt = BufSize;
- InputPending = charp();
- }
- }
- }
- #endif /* !(defined(BSD4_2) && !defined(BSD2_10)) */
- }
- #else /* MSDOS */
-
- long start,
- end;
- #ifndef IBMPC
- struct dostime_t tc;
- #endif
-
- redisplay();
- #ifdef IBMPC
- _bios_timeofday(_TIME_GETCLOCK, &start);
- #else
- _dos_gettime(&tc);
- start = (long)(tc.hour*60L*60L*10L)+(long)(tc.minute*60L*10L)+
- (long)(tc.second*10)+(long)(tc.hsecond/10);
- #endif
- end = (start + delay);
- do {
- if ((InputPending = charp()) != NO)
- break;
- #ifdef IBMPC
- if (_bios_timeofday(_TIME_GETCLOCK, &start))
- break; /* after midnight */
- #else
- start = (long)(tc.hour*60L*60L*10L)+(long)(tc.minute*60L*10L)+
- (long)(tc.second*10)+(long)(tc.hsecond/10);
- #endif
- } while (start < end);
- #endif /* MSDOS */
- #endif /* !MAC */
- }
-
- bool
- sindex(pattern, string)
- register char *pattern,
- *string;
- {
- register size_t len = strlen(pattern);
-
- while (*string != '\0') {
- if (*pattern == *string && strncmp(pattern, string, len) == 0)
- return TRUE;
- string += 1;
- }
- return FALSE;
- }
-
- void
- make_argv(argv, ap)
- register char *argv[];
- va_list ap;
- {
- register int i = 0;
-
- argv[i++] = va_arg(ap, char *);
- argv[i++] = basename(argv[0]);
- do ; while ((argv[i++] = va_arg(ap, char *)) != NULL);
- }
-
- int
- pnt_line()
- {
- register Line *lp = curbuf->b_first;
- register int i;
-
- for (i = 0; lp != NULL; i++, lp = lp->l_next)
- if (lp == curline)
- break;
- return i + 1;
- }
-
- /* Free, then allocate a block.
- * Like erealloc, except that the previous contents of the block are lost.
- */
-
- UnivPtr
- freealloc(obj, size)
- register UnivPtr obj;
- size_t size;
- {
- register UnivPtr new = NULL;
-
- if (obj)
- new = realloc(obj, size);
- if (new == NULL)
- new = emalloc(size);
- return new;
- }
-
- #ifndef HAVE_STRERROR
- /*
- * Unix version of strerror - map error number to descriptive string.
- * ANSI systems should have this.
- */
- char *
- strerror(errnum)
- int errnum;
- {
- extern int sys_nerr;
- extern char *sys_errlist[];
-
- if (errnum > 0 && errnum < sys_nerr)
- return(sys_errlist[errnum]);
- return sprint("Error number %d", errnum);
- }
- #endif
-